﻿using ConfigInfoWebPlatform.API.BusinessCommon;
using ConfigInfoWebPlatform.API.DBCommon;
using ConfigInfoWebPlatform.Model;
using ConfigInfoWebPlatform.Nlog;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

namespace ConfigInfoWebPlatform.API.Controllers
{
    /// <summary>
    /// 版本管理控制器
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class VersionController : ControllerBase
    {
        readonly LogHelper _log;
        readonly string configRootPath;
        readonly string initDB;

        /// <summary>
        /// 版本管理控制器
        /// </summary>
        public VersionController(LogHelper logHelper, IConfiguration configuration)
        {
            _log = logHelper;
            configRootPath = configuration["AppSetting:configPath"].ToString();
            initDB = configuration["AppSetting:initDB"].ToString();
        }

        /// <summary>
        /// 分页获取版本列表数据
        /// </summary>
        [HttpGet("index")]
        public IActionResult Index(int page, int limit)
        {
            List<VersionModel> list = new List<VersionModel>();
            List<VersionModel> pageList = new List<VersionModel>();
            //用户信息
            UserInfoModel user = new UserInfoModel();
            var jsonStr = Base64Helper.DeCodeBase64(65001, Request.Headers["user"]);
            user = Newtonsoft.Json.JsonConvert.DeserializeObject<UserInfoModel>(jsonStr);
            //获取所有版本数据
            DAL_Version versionDal = new DAL_Version();
            list = versionDal.GetVersionList(user.D_id, user.Name == "admin" ? true : false);
            int totalcount = 0;
            if (list.Any())
            {
                totalcount = list.Count;
                pageList = list.Skip((page - 1) * limit).Take(limit).ToList();
            }
            return new JsonResult(new { code = 0, msg = "success", count = totalcount, data = pageList });
        }

        /// <summary>
        /// 版本详细信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("detail")]
        public IActionResult Detial(string id)
        {
            VersionModel version = new VersionModel();
            DAL_Version versionDal = new DAL_Version();
            version = versionDal.GetVersionDetail(id);
            return new JsonResult(new { code = 0, msg = "success", data = version });
        }

        /// <summary>
        /// 保存版本信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost("saveversion")]
        public IActionResult SaveVersion(VersionModel model)
        {
            DAL_Version versionDal = new DAL_Version();
            int result = 0;
            string resultMsg = "success";
            var jsonStr = Base64Helper.DeCodeBase64(65001, Request.Headers["user"]);
            UserInfoModel user = Newtonsoft.Json.JsonConvert.DeserializeObject<UserInfoModel>(jsonStr);
            model.Did = user.D_id;
            if (!versionDal.IsExists(model.Name,model.Id))
            {
                if (string.IsNullOrWhiteSpace(model.Id))
                {
                    result = versionDal.InsertVersion(model);
                    if (result > 0)
                    {
                        var versionPath = model?.Catalogue == "dev"
                                        ? ""
                                        : model?.Catalogue;
                        string dirpath = Path.Combine(configRootPath, versionPath).Replace("\\", "/");
                        if (!Directory.Exists(dirpath))
                        {
                            Directory.CreateDirectory(dirpath);
                            CopyFolder($"{configRootPath}/config", $"{dirpath}/config");
                        }
                    }
                }
                else
                    result = versionDal.EditVersion(model);
            }
            else
                resultMsg = $"此版本名称已存在";
            return new JsonResult(new
            {
                code = result > 0 ? 0 : 1,
                msg = resultMsg
            });

        }

        /// <summary>
        /// 删除组织信息
        /// </summary>
        [HttpPost("deleteversion")]
        public IActionResult DeleteVersion(string id)
        {
            DAL_Version versionDal = new DAL_Version();
            int resultCode = 0;
            string resultMsg = "删除失败";
            var version = versionDal.GetVersionDetail(id);
            if (version!=null&& !string.IsNullOrWhiteSpace(version.Id))
            {
                resultCode = versionDal.DeleteVersion(id);
                if (resultCode > 0)
                    resultMsg = "删除成功";
            }
            else
                resultMsg = "该版本不存在或已被删除";
            if(resultCode>0)
            {
                string filepath = Path.Combine(configRootPath, version?.Catalogue ?? "").Replace("\\", "/");
                var catalogue = $"{version?.Catalogue}back{DateTime.Now.ToString("yyyyMMddHHmmss")}";
                string newPath= Path.Combine(configRootPath, catalogue).Replace("\\", "/");
                if (!Directory.Exists(filepath))
                    Directory.Move(filepath,newPath);
            }

            return new JsonResult(new
            {
                code = resultCode > 0 ? 0 : 1,
                msg = resultMsg
            });
        }

        
        /// <summary>
        /// 获取流程树
        /// </summary>
        /// <returns></returns>
        [HttpGet("getprocesstree")]
        public IActionResult GetProcessTree()
        {
            //DAL_ProgramNavicat _programNavicat = new DAL_ProgramNavicat();
            //var programNavicats = _programNavicat.GetProcessmNavicatInfos();
            //var processNavs = programNavicats.Where(x =>x.Id.StartsWith("1001")).ToList();
            return new JsonResult(new
            {
                code = 0,
                msg = "success"
            });
        }

        /// <summary>
        /// 打包下载流程配置文件
        /// </summary>
        /// <returns></returns>
        [HttpPost("packagDown")]
        public async Task<IActionResult> packagDown(PackagModel dirs)
        {
            string zipName = Path.Combine(System.Environment.CurrentDirectory, "judgedocsystem.zip");
            CreateZip(Request, dirs, zipName);
            //要下载的文件地址，这个文件会被分成片段，通过循环逐步读取到ASP.NET Core中，然后发送给客户端浏览器
            var fileName = Path.GetFileName(zipName);

            int bufferSize = 500;//这就是ASP.NET Core循环读取下载文件的缓存大小，这里我们设置为了1024字节，也就是说ASP.NET Core每次会从下载文件中读取1024字节的内容到服务器内存中，然后发送到客户端浏览器，这样避免了一次将整个下载文件都加载到服务器内存中，导致服务器崩溃

            Response.ContentType = "application/x-zip-compressed";//由于我们下载的是一个Excel文件，所以设置ContentType为application/vnd.ms-excel
            Response.Headers.Add("Connection", "Keep-Alive");
            var contentDisposition = "attachment;" + "filename=" + HttpUtility.UrlEncode(fileName);//在Response的Header中设置下载文件的文件名，这样客户端浏览器才能正确显示下载的文件名，注意这里要用HttpUtility.UrlEncode编码文件名，否则有些浏览器可能会显示乱码文件名
            Response.Headers.Add("Content-Disposition", new string[] { contentDisposition });

            //使用FileStream开始循环读取要下载文件的内容
            using (FileStream fs = new FileStream(zipName, FileMode.Open, FileAccess.Read))
            {
                using (Response.Body)//调用Response.Body.Dispose()并不会关闭客户端浏览器到ASP.NET Core服务器的连接，之后还可以继续往Response.Body中写入数据
                {
                    long contentLength = fs.Length;//获取下载文件的大小
                    Response.ContentLength = contentLength;//在Response的Header中设置下载文件的大小，这样客户端浏览器才能正确显示下载的进度
                    byte[] buffer;
                    long hasRead = 0;//变量hasRead用于记录已经发送了多少字节的数据到客户端浏览器
                    //如果hasRead小于contentLength，说明下载文件还没读取完毕，继续循环读取下载文件的内容，并发送到客户端浏览器
                    while (hasRead < contentLength)
                    {
                        //HttpContext.RequestAborted.IsCancellationRequested可用于检测客户端浏览器和ASP.NET Core服务器之间的连接状态，如果HttpContext.RequestAborted.IsCancellationRequested返回true，说明客户端浏览器中断了连接
                        if (HttpContext.RequestAborted.IsCancellationRequested)
                        {
                            //如果客户端浏览器中断了到ASP.NET Core服务器的连接，这里应该立刻break，取消下载文件的读取和发送，避免服务器耗费资源
                            break;
                        }
                        buffer = new byte[bufferSize];
                        int currentRead = fs.ReadAsync(buffer, 0, bufferSize).Result;//从下载文件中读取bufferSize(1024字节)大小的内容到服务器内存中
                        await Response.Body.WriteAsync(buffer, 0, currentRead);//发送读取的内容数据到客户端浏览器
                        await Response.Body.FlushAsync();//注意每次Write后，要及时调用Flush方法，及时释放服务器内存空间
                        hasRead += currentRead;//更新已经发送到客户端浏览器的字节数
                        await Task.Delay(100);
                    }
                }
            }
            return new EmptyResult();
        }


        private void CreateZip(HttpRequest request, PackagModel dirs,string fileName)
        {
            #region 获取用户、版本
            //获取用户信息
            UserInfoModel user = new UserInfoModel();
            var userJsonStr = Base64Helper.DeCodeBase64(65001, request.Headers["user"]);
            user = Newtonsoft.Json.JsonConvert.DeserializeObject<UserInfoModel>(userJsonStr);
            //获取版本信息
            VersionModel version = new VersionModel();
            var versionJsonStr = Base64Helper.DeCodeBase64(65001, request.Headers["version"]);
            version = Newtonsoft.Json.JsonConvert.DeserializeObject<VersionModel>(versionJsonStr);
            var versionPath = version?.Catalogue == "dev"
                                ? ""
                                : version?.Catalogue;
            #endregion
            string zipDir = Path.Combine(System.Environment.CurrentDirectory, "zip");
            //先判断是否保存有上次打包的压缩文件
            if (System.IO.File.Exists(fileName))
            {
                System.IO.File.Delete(fileName);
            }
            if (!Directory.Exists(zipDir))
                Directory.CreateDirectory(zipDir);
            foreach (var dir in dirs.Dirs)
            {
                string sourceDir = Path.Combine(configRootPath, versionPath, dir);
                string destDir = sourceDir.Replace(configRootPath, zipDir);
                CopyFolder(sourceDir, destDir);
            }
            ZipHelper.CreateZip(zipDir, fileName);
            Task.Run(() => { DeleteFolder(zipDir); });
            
        }

        /// <summary>
        /// 复制文件夹及文件
        /// </summary>
        /// <param name="sourceFolder">原文件路径</param>
        /// <param name="destFolder">目标文件路径</param>
        private int CopyFolder(string sourceFolder, string destFolder)
        {
            try
            {
                //如果目标路径不存在,则创建目标路径
                if (!System.IO.Directory.Exists(destFolder))
                {
                    System.IO.Directory.CreateDirectory(destFolder);
                }
                //得到原文件根目录下的所有文件
                string[] files = System.IO.Directory.GetFiles(sourceFolder);
                foreach (string file in files)
                {
                    string name = System.IO.Path.GetFileName(file);
                    string dest = System.IO.Path.Combine(destFolder, name);
                    System.IO.File.Copy(file, dest);//复制文件
                }
                //得到原文件根目录下的所有文件夹
                string[] folders = System.IO.Directory.GetDirectories(sourceFolder);
                foreach (string folder in folders)
                {
                    string name = System.IO.Path.GetFileName(folder);
                    string dest = System.IO.Path.Combine(destFolder, name);
                    CopyFolder(folder, dest);//构建目标路径,递归复制文件
                }
                return 1;
            }
            catch (Exception e)
            {
                return 0;
            }

        }

        /// <summary>
        /// 删除目录
        /// </summary>
        /// <param name="dir">要删除的目录</param>
        private void DeleteFolder(string dir)
        {
            if (System.IO.Directory.Exists(dir))
            {
                string[] fileSystemEntries = System.IO.Directory.GetFileSystemEntries(dir);
                for (int i = 0; i < fileSystemEntries.Length; i++)
                {
                    string text = fileSystemEntries[i];
                    if (System.IO.File.Exists(text))
                    {
                        System.IO.File.Delete(text);
                    }
                    else
                    {
                        DeleteFolder(text);
                    }
                }
                System.IO.Directory.Delete(dir);
            }
        }

    }
}
